package tech

//*
import (
	"errors"
	"fmt"
	"ssp/set"

	"os"
	"regexp"

	"strconv"
	"strings"
)

func calcBoxAndCellNum(rowNum int, colNum int) (boxNum int, cellNum int) {
	boxNum = rowNum/3*3 + colNum/3
	cellNum = rowNum%3*3 + colNum%3
	return
}

func calcRowAndColNum(boxNum int, cellNum int) (rowNum int, colNum int) {
	rowNum = boxNum/3*3 + cellNum/3
	colNum = boxNum%3*3 + cellNum%3
	return
}

type Cell struct {
	value   int
	cands   set.Set
	rowNum  int
	colNum  int
	boxNum  int
	cellNum int
	given   bool
}

func toCand(value int) int {
	return value - 1
}

func toValue(cand int) int {
	return cand + 1
}

func (c Cell) filled() bool {
	return c.solved() && !c.given
}
func (c Cell) String() string {
	if c.value == 0 {
		return fmt.Sprintf("r%vc%v[%s]", c.rowNum+1, c.colNum+1, c.cands.ValueString())
	} else if c.given {
		return fmt.Sprintf("r%vc%v{%v}", c.rowNum+1, c.colNum+1, c.value)
	} else {
		return fmt.Sprintf("r%vc%v(%v)", c.rowNum+1, c.colNum+1, c.value)
	}
}

func (c Cell) solved() bool {
	return c.value != 0
}

func (c *Cell) setValue(value int) {
	c.value = value
	if value == 0 {
		c.cands.Full()
	} else {
		c.cands.Empty()
	}
}

func (c *Cell) removeCandBut(cand int) (used bool) {
	if c.solved() {
		return false
	}
	temp := c.cands
	c.cands = c.cands.Intersect(set.NewSet(cand))
	return c.cands == temp
}

func (c *Cell) removeCandsBut(cands set.Set) (used bool) {
	if c.solved() {
		return
	}
	return c.cands.RemoveAllBut(cands)
}

func removeCandsBut(cands set.Set, cells []*Cell) {
	for _, cell := range cells {
		cell.removeCandsBut(cands)
	}
}

func (c *Cell) removeCand(cand int) (used bool) {
	if c.solved() {
		return
	}
	return c.cands.Delete(cand)
}

func (c *Cell) canRemoveCand(cand int) (used bool) {
	return !c.solved() && c.cands.Has(cand)
}

func (c *Cell) canRemoveCands(cands set.Set) (used bool) {
	return !c.solved() && c.cands.HasAny(cands)
}

func removeCands(cands set.Set, cells []*Cell) {
	for _, cell := range cells {
		cell.removeCands(cands)
	}
}
func (c *Cell) removeCands(cands set.Set) (used bool) {
	if c.solved() {
		return
	}
	return c.cands.DeleteAll(cands)
}

func (c *Cell) Equal(other *Cell) bool {
	return c.rowNum == other.rowNum && c.colNum == other.colNum
}

func (c *Cell) isMemberOf(cs []*Cell) bool {
	for _, cell := range cs {
		if c.Equal(cell) {
			return true
		}
	}
	return false
}

type House struct {
	solvedCount int
	kind        int
	cells       [9]*Cell
}

func (h House) String() string {
	switch h.kind {
	case 0:
		return fmt.Sprintf("R%v", h.cells[0].rowNum+1)
	case 1:
		return fmt.Sprintf("C%v", h.cells[0].colNum+1)
	default:
		return fmt.Sprintf("B%v", h.cells[0].boxNum+1)
	}
}

type Grid struct {
	solvedCount int
	cells       [9][9]Cell
	rows        [9]House
	cols        [9]House
	boxes       [9]House
	houses      []*House
	lines       []*House
	allCells    []*Cell
}

func (g *Grid) GetSolvedCount() int {
	return g.solvedCount
}

func (g *Grid) GetCells() [][]*Cell {
	cells := make([][]*Cell, 0)
	for _, row := range g.rows {
		cells = append(cells, row.cells[:])
	}
	return cells
}

func (g *Grid) CheckInput() error {
	if len(os.Args) == 1 {
		fmt.Println("You must provide a sudoku string.")
		return errors.New("input error")
	}

	if len(os.Args[1]) < 81 {
		fmt.Println("The sudoku string must be 81 characters long.")
		return errors.New("input error")
	}

	for _, value := range os.Args[1] {
		if value < '0' || value > '9' {
			fmt.Println("The sudokku string must only cantain 0 to 9 digits.")
			return errors.New("input error")
		}
	}

	return nil
}

func (g *Grid) Input(in string) {
	buff := [81]uint8{}
	pos := 0
	for _, c := range []byte(in) {
		if c >= '0' && c <= '9' {
			buff[pos] = c - '0'
			pos++
		}
		if c == '.' {
			pos++
		}
		if pos == 81 {
			break
		}
	}

	pos = 0
	g.solvedCount = 0
	for rowNum := 0; rowNum < 9; rowNum++ {
		for colNum := 0; colNum < 9; colNum++ {
			g.cells[rowNum][colNum].setValue(int(buff[pos]))
			pos++
			if g.cells[rowNum][colNum].value != 0 {
				g.solvedCount++
				g.cells[rowNum][colNum].given = true
			}
		}
	}
}

func (g *Grid) Solved() bool {
	return g.solvedCount == 81
}

func (g *Grid) Init() {
	g.initRows()
	g.initCols()
	g.initBoxes()

	g.lines = make([]*House, 9*2)
	for i := range 9 {
		g.lines[i] = &g.rows[i]
	}
	for i := range 9 {
		g.lines[9+i] = &g.cols[i]
	}

	g.houses = make([]*House, 9*3)
	for i := range 9 {
		g.houses[i] = &g.boxes[i]
	}
	for i := range 2 * 9 {
		g.houses[9+i] = g.lines[i]
	}
	for _, row := range g.rows {
		g.allCells = append(g.allCells, row.cells[:]...)
	}
}

func (g *Grid) initRows() {
	for rowNum := 0; rowNum < 9; rowNum++ {
		g.rows[rowNum].solvedCount = 0
		g.rows[rowNum].kind = 0
		for colNum := 0; colNum < 9; colNum++ {
			g.rows[rowNum].cells[colNum] = &g.cells[rowNum][colNum]
			if g.cells[rowNum][colNum].solved() {
				g.rows[rowNum].solvedCount += 1
			}
		}
	}
}

func (g *Grid) initCols() {
	for colNum := 0; colNum < 9; colNum++ {
		g.cols[colNum].solvedCount = 0
		g.cols[colNum].kind = 1
		for rowNum := 0; rowNum < 9; rowNum++ {
			g.cols[colNum].cells[rowNum] = &g.cells[rowNum][colNum]
			if g.cells[rowNum][colNum].solved() {
				g.cols[colNum].solvedCount += 1
			}
		}
	}
}

func (g *Grid) initBoxes() {
	for boxNum := 0; boxNum < 9; boxNum++ {
		g.boxes[boxNum].solvedCount = 0
		g.boxes[boxNum].kind = 2
		for cellNum := 0; cellNum < 9; cellNum++ {
			rowNum, colNum := calcRowAndColNum(boxNum, cellNum)
			g.cells[rowNum][colNum].rowNum = rowNum
			g.cells[rowNum][colNum].colNum = colNum
			g.cells[rowNum][colNum].boxNum = boxNum
			g.cells[rowNum][colNum].cellNum = cellNum
			g.boxes[boxNum].cells[cellNum] = &g.cells[rowNum][colNum]
			if g.cells[rowNum][colNum].solved() {
				g.boxes[boxNum].solvedCount += 1
			}
		}
	}
}

func printBoldBorder() {
	fmt.Println("++===+===+===++===+===+===++===+===+===++")
}

func printFineBorder() {
	fmt.Println("++---+---+---++---+---+---++---+---+---++")
}

func (g *Grid) printLineOfRow(row House, lineNum int) {
	fmt.Print("||")
	for colNum, cell := range row.cells {
		if cell.solved() {
			if lineNum == 1 {
				fmt.Printf("(%d)", cell.value)
			} else {
				fmt.Print("   ")
			}
		} else {
			start := lineNum*3 + 1
			for i := start; i < start+3; i++ {
				if cell.cands.Has(toCand(i)) {
					fmt.Printf("%d", i)
				} else {
					fmt.Print(" ")
				}
			}
		}
		if (colNum+1)%3 == 0 {
			fmt.Print("||")
		} else {
			fmt.Print("|")
		}
	}
	fmt.Println()
}

func (g *Grid) printRow(row House) {
	g.printLineOfRow(row, 0)
	g.printLineOfRow(row, 1)
	g.printLineOfRow(row, 2)
}

func (g *Grid) PrintGrid() {
	if g.solvedCount == 81 {
		g.printSimply()
		return
	}
	printBoldBorder()
	for rowNum, row := range g.rows {
		g.printRow(row)
		if (rowNum+1)%3 == 0 {
			printBoldBorder()
		} else {
			printFineBorder()
		}
	}
}

func (g *Grid) printSimply() {
	for i := 0; i < 9; i++ {
		for j := 0; j < 9; j++ {
			fmt.Print(g.cells[i][j].value)
			if (j+1)%3 == 0 {
				fmt.Print(" ")
			}
		}
		fmt.Println()
		if (i+1)%3 == 0 {
			fmt.Println()
		}
	}
}

// */
func clearupHouse(house House, solvedNum int) {
	cand := toCand(house.cells[solvedNum].value)
	for i, cell := range house.cells {
		if i == solvedNum || cell.solved() {
			continue
		}
		cell.removeCand(cand)
	}
}

func (g *Grid) Clearup() {
	for rowNum := 0; rowNum < 9; rowNum++ {
		for colNum := 0; colNum < 9; colNum++ {
			if !g.cells[rowNum][colNum].solved() {
				continue
			}
			clearupHouse(g.rows[rowNum], colNum)
			clearupHouse(g.cols[colNum], rowNum)
			boxNum, cellNum := calcBoxAndCellNum(rowNum, colNum)
			clearupHouse(g.boxes[boxNum], cellNum)
		}
	}
}

func (h *House) KindName() string {
	names := [3]string{"Row", "Col", "Box"}
	return names[h.kind]
}

func (g *Grid) Values() string {
	var b strings.Builder
	for _, row := range g.rows {
		for _, cell := range row.cells {
			b.WriteString(strconv.Itoa(cell.value))
		}
	}

	return b.String()
}

func (g *Grid) GivensValues() string {
	var b strings.Builder
	for i := range 9 {
		for j := range 9 {
			if g.cells[i][j].given {
				fmt.Fprintf(&b, "%v", g.cells[i][j].value)
			} else {
				fmt.Fprintf(&b, "%v", "0")
			}
		}
	}

	return b.String()
}
func (g *Grid) Decode(s string) (ok bool) {
	re := regexp.MustCompile(`(\[\d+\])|(\(\d\))|(\{\d\})|\d|\.`)
	all := re.FindAllString(s, -1)
	for range 81 - len(all) {
		all = append(all, "0")
	}
	rowNum := 0
	colNum := 0
	g.solvedCount = 0
	for _, v := range all {
		cell := &g.cells[rowNum][colNum]
		switch {
		case v == "." || v == "0": // 处理点号
			cell.setValue(0)
			cell.cands.Full()
		case strings.HasPrefix(v, "["): // 处理方括号项（如[123]）
			digits := v[1 : len(v)-1] // 提取括号内数字（如"123"）
			for _, d := range digits {
				cell.cands.Add(toCand(int(d - '0')))
			}
		case strings.HasPrefix(v, "("): // 处理圆括号项（如(5)）
			digit := v[1] - '0' // 提取括号内数字（如'5'→5）
			cell.setValue(int(digit))
			g.solvedCount++
		case strings.HasPrefix(v, "{"): // 处理花括号项（如{7}）
			digit := v[1] - '0' // 提取括号内数字（如'7'→7）
			cell.setValue(int(digit))
			cell.given = true // 假设花括号表示给定数字
			g.solvedCount++
		default: // 处理纯数字（如"3"）
			digit := v[0] - '0'
			cell.setValue(int(digit))
			cell.given = true
			g.solvedCount++
		}
		colNum++
		if colNum == 9 {
			rowNum++
			colNum = 0
		}
	}
	ok = true
	return
}

func (g *Grid) Encode() string {
	var b strings.Builder
	for i := 0; i < 9; i++ {
		for j := 0; j < 9; j++ {
			if !g.cells[i][j].solved() {
				fmt.Fprintf(&b, "[%v]", g.cells[i][j].cands.ValueString())
			} else if g.cells[i][j].given {
				fmt.Fprintf(&b, "%v", g.cells[i][j].value)
			} else {
				fmt.Fprintf(&b, "(%v)", g.cells[i][j].value)
			}
			if (j+1)%3 == 0 {
				fmt.Fprint(&b, " ")
			}
		}
		fmt.Fprintln(&b)
		if (i+1)%3 == 0 {
			fmt.Fprintln(&b)
		}
	}
	return b.String()
}
